// region:    --- Tests
#[cfg(test)]
mod tests {
    pub type Result<T> = core::result::Result<T, Error>;
    pub type Error = Box<dyn std::error::Error>; // For tests.

    use crate::_dev_utils;
    use crate::model::ModelManager;
    use crate::{
        ctx::Ctx,
        model::{
            self, base,
            user::{User, UserBmc, UserForCreate},
        },
    };
    use modql::filter::OpValString;
    use serial_test::serial;

    #[allow(dead_code)]
    async fn seed_users(ctx: &Ctx, mm: &ModelManager, usernames: &[&str]) -> Result<Vec<i64>> {
        let mut ids = Vec::new();
        for name in usernames {
            let id = seed_user(ctx, mm, name).await?;
            ids.push(id);
        }

        Ok(ids)
    }

    #[allow(dead_code)]
    async fn seed_user(ctx: &Ctx, mm: &ModelManager, username: &str) -> model::Result<i64> {
        let id = UserBmc::create(
            ctx,
            mm,
            UserForCreate {
                username: username.to_string(),
                ..Default::default()
            },
        )
        .await?;
        Ok(id)
    }

    #[allow(dead_code)]
    async fn clean_users(
        ctx: &Ctx,
        mm: &ModelManager,
        contains_username: &str,
    ) -> model::Result<usize> {
        let users = UserBmc::list(
            ctx,
            mm,
            Some(vec![model::user::UserFilter {
                username: Some(OpValString::Contains(contains_username.to_string()).into()),
                ..Default::default()
            }]),
            None,
        )
        .await?;

        let count = users.len();
        for user in users {
            base::delete::<UserBmc>(ctx, mm, user.id).await?;
        }
        Ok(count)
    }

    #[serial]
    #[tokio::test]
    async fn test_create_ok() -> Result<()> {
        // -- Setup & Fixtures
        let mm = _dev_utils::init_test().await;
        let ctx = Ctx::root_ctx();
        let fx_username = "test_create_ok-user-01";
        // -- Exec
        let user_id = UserBmc::create(
            &ctx,
            &mm,
            UserForCreate {
                username: fx_username.to_string(),
                ..Default::default()
            },
        )
        .await?;
        // -- Check
        let user: User = UserBmc::get(&ctx, &mm, user_id).await?;
        assert_eq!(user.username, fx_username);

        // -- Clean
        base::delete::<UserBmc>(&ctx, &mm, user_id).await?;
        Ok(())
    }

    #[serial]
    #[tokio::test]
    async fn test_first_ok_demo1() -> Result<()> {
        let mm = _dev_utils::init_test().await;
        let ctx = Ctx::root_ctx();
        let fx_username = "demo1";

        let user: User = UserBmc::first_by_username(&ctx, &mm, fx_username)
            .await?
            .ok_or("should have user 'demo1'")?;

        assert_eq!(user.username, fx_username);
        Ok(())
    }

    #[serial]
    #[tokio::test]
    async fn test_seed_user() -> Result<()> {
        let mm = _dev_utils::init_test().await;
        let ctx = Ctx::root_ctx();
        let fx_username = "seed_user";
        let id: i64 = seed_user(&ctx, &mm, fx_username).await?;

        let user: User = UserBmc::get(&ctx, &mm, id).await?;
        assert_eq!(user.username, fx_username);
        base::delete::<UserBmc>(&ctx, &mm, id).await?;
        Ok(())
    }
}
